package com.smart.cosstarter.aspect;

import com.smart.cosstarter.annotation.CreateBucket;
import com.smart.cosstarter.config.COSBucketsManager;
import com.smart.cosstarter.exception.NoBucketExeception;
import com.qcloud.cos.model.AccessControlList;
import com.qcloud.cos.model.Bucket;
import com.qcloud.cos.model.CannedAccessControlList;
import com.qcloud.cos.model.SetBucketAclRequest;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

/**
 * @Author: jj
 * @Date: 2019/8/7 15:15
 * @Version 1.0
 */
@Component
@Aspect
public class BucketAspect {

	@Autowired
	private COSBucketsManager cosBucketsManager;

	@Pointcut("@annotation(com.smart.cosstarter.annotation.CreateBucket)")
	public void createBucketAspect() {
	}
	@Pointcut("@annotation(com.smart.cosstarter.annotation.UseCOS)")
	public void useBucketAspect() {
	}

	Bucket bucket = null;

	@Before("createBucketAspect()")
	public void createDoBefore(JoinPoint joinPoint) {
		try {
			MethodSignature signature = (MethodSignature)joinPoint.getSignature();
			String targetName = joinPoint.getTarget().getClass().getName();
			String name = signature.getName();
			Class targetClass = Class.forName(targetName);
			Method[] methods = targetClass.getMethods();
			Object[] arguments = joinPoint.getArgs();
			for (Method method : methods) {
				if (method.getName().equals(name)){
					CreateBucket annotation = AnnotationUtils.findAnnotation(method, CreateBucket.class);
					if (!"".equals(annotation.bucketName())) {
						bucket = cosBucketsManager.createBucket(annotation.bucketName());
						cosBucketsManager.setBucketAcl(annotation.bucketName(),annotation.bucketACL());
					}else {
						Class<?>[] parameterTypes = method.getParameterTypes();
						int parameterCount = method.getParameterCount();
						for (int i = 0; i < parameterTypes.length; i++) {
							Class<?> parameterType = parameterTypes[i];
							if (SetBucketAclRequest.class.getName().equals(parameterType.getName())) {
								SetBucketAclRequest argument = (SetBucketAclRequest) arguments[i];
								bucket = cosBucketsManager.createBucket(argument.getBucketName());
								cosBucketsManager.setBucketAcl(argument);
							}
							if (String.class.getName().equals(parameterType.getName())) {
								if (arguments[i] != null && !"".equals(arguments[i])){
									bucket = cosBucketsManager.createBucket((String) arguments[i]);
									if (parameterCount > 1){
										for (int j = 0; j < parameterTypes.length; j++) {
											if (AccessControlList.class.getName().equals(parameterType.getName())) {
												AccessControlList argument = (AccessControlList) arguments[j];
												cosBucketsManager.setBucketAcl((String)arguments[i],argument);
											}
											if (CannedAccessControlList.class.getName().equals(parameterType.getName())) {
												CannedAccessControlList argument = (CannedAccessControlList) arguments[j];
												cosBucketsManager.setBucketAcl((String)arguments[i],argument);
											}
										}
									}
								}
							}
						}
					}
				}
			}
			if (bucket == null){
				throw new NoBucketExeception();
			}
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
	}

	@AfterReturning(pointcut = "createBucketAspect()", returning = "ret")
	public Object createDoAfter(JoinPoint joinPoint, Object ret) {
		if (bucket != null){
			if (ret instanceof Bucket){
				return bucket;
			}
			if (ret.getClass().getTypeName().equals(Object.class.getTypeName())){
				return bucket;
			}
			if (ret instanceof String){
				return bucket.toString();
			}
			if (ret instanceof Integer){
				return bucket.hashCode();
			}
			if (ret instanceof Boolean){
				return true;
			}
		}
		return ret;
	}

}
